﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ComprUtils
{
  using System;
  using System.Runtime.InteropServices;

  public enum RarOperations
  {
    RAR_OP_SKIP, RAR_OP_TEST, RAR_OP_EXTRACT
  }
  public enum RarOpenMode
  { RAR_OM_LIST, RAR_OM_EXTRACT }

  public enum RarVol
  { RAR_VOL_ASK, RAR_VOL_NOTIFY }

  public enum RarCallbackMessages
  {
    UCM_CHANGEVOLUME, UCM_PROCESSDATA, UCM_NEEDPASSWORD
  }

  public struct RAROpenArchiveData
  {
    public string ArcName;
    public uint OpenMode;
    public uint OpenResult;
    public string CmtBuf;
    public uint CmtBufSize;
    public uint CmtSize;
    public uint CmtState;
  }

  public struct RAROpenArchiveDataEx
  {
    public string ArcName;
    public string ArcNameW;
    public RarOpenMode OpenMode;
    public uint OpenResult;
    public string CmtBuf;
    public uint CmtBufSize;
    public uint CmtSize;
    public uint CmtState;
    public uint Flags;
    public uint Reserved;
  }

  public struct RARHeaderData
  {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string ArcName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string FileName;
    public uint Flags;
    public uint PackSize;
    public uint UnpSize;
    public uint HostOS;
    public uint FileCRC;
    public uint FileTime;
    public uint UnpVer;
    public uint Method;
    public uint FileAttr;
    public string CmtBuf;
    public uint CmtBufSize;
    public uint CmtSize;
    public uint CmtState;
  }

  public struct RARHeaderDataEx
  {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
    public string ArcName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2048)]
    public string ArcNameW;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
    public string FileName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2048)]
    public string FileNameW;
    public uint Flags;
    public uint PackSize;
    public uint PackSizeHigh;
    public uint UnpSize;
    public uint UnpSizeHigh;
    public uint HostOS;
    public uint FileCRC;
    public uint FileTime;
    public uint UnpVer;
    public uint Method;
    public uint FileAttr;
    public string CmtBuf;
    public uint CmtBufSize;
    public uint CmtSize;
    public uint CmtState;
    public uint Reserved;
  };

  /// <summary>
  /// Summary description for Unrar.
  /// </summary>
  public class UnRarInterop
  {
    public const int ERAR_END_ARCHIVE = 10;
    public const int ERAR_NO_MEMORY = 11;
    public const int ERAR_BAD_DATA = 12;
    public const int ERAR_BAD_ARCHIVE = 13;
    public const int ERAR_UNKNOWN_FORMAT = 14;
    public const int ERAR_EOPEN = 15;
    public const int ERAR_ECREATE = 16;
    public const int ERAR_ECLOSE = 17;
    public const int ERAR_EREAD = 18;
    public const int ERAR_EWRITE = 19;
    public const int ERAR_SMALL_BUF = 20;


    [DllImportAttribute("unrar.dll")]
    public static extern IntPtr RAROpenArchive(ref RAROpenArchiveData ArchiveData);
    [DllImportAttribute("unrar.dll")]
    public static extern int RARCloseArchive(IntPtr hArcData);
    [DllImportAttribute("unrar.dll")]
    public static extern int RARReadHeader(IntPtr hArcData, ref RARHeaderData HeaderData);
    [DllImportAttribute("unrar.dll")]
    public static extern IntPtr RAROpenArchiveEx(ref RAROpenArchiveDataEx ArchiveData);
    [DllImportAttribute("unrar.dll")]
    public static extern int RARReadHeaderEx(IntPtr hArcData, ref RARHeaderDataEx HeaderData);
    [DllImportAttribute("unrar.dll")]
    public static extern int RARProcessFile(IntPtr hArcData, RarOperations
    Operation, string DestPath, string DestName);
    [DllImportAttribute("unrar.dll")]
    public static extern int RARGetDllVersion();
    [DllImportAttribute("unrar.dll")]
    public static extern int RARSetPassword(IntPtr hArcData,string ArchivePwd);
    [DllImportAttribute("unrar.dll")]
    public static extern int RARSetCallback(IntPtr hArcData,
      RarCallbackProcDelegate RarCallbackProc, IntPtr UserData);
    public delegate int RarCallbackProcDelegate(RarCallbackMessages msg, IntPtr UserData, IntPtr P1, int P2);

    [STAThread]
    static void Main(string[] args)
    {
      IntPtr lHandle;
      int iStatus = 0,iStatus2=0; 
      string ArchivePwd=null,sDestPath;
      RARHeaderDataEx uHeader = new RARHeaderDataEx();
      RAROpenArchiveDataEx uRAR = new RAROpenArchiveDataEx();

      uRAR.ArcName = @"x:\temp\TestUnrar\ScreenSaver1.rar";
      sDestPath = Path.GetDirectoryName(uRAR.ArcName)+"\\";
      uRAR.CmtBuf = string.Empty.PadLeft(16384, ' ');
      uRAR.CmtBufSize = 16384;
      uHeader.CmtBuf = string.Empty.PadLeft(16384, ' ');
      uHeader.CmtBufSize = 16384;
      // open for list
      uRAR.OpenMode = RarOpenMode.RAR_OM_LIST;
      lHandle = RAROpenArchiveEx(ref uRAR);
      Console.WriteLine("OpenResult: {0}", uRAR.OpenResult);
      Console.WriteLine("CmtState: {0}", uRAR.CmtState);
      //if(!string.IsNullOrEmpty(ArchivePwd))
      //  RARSetPassword(lHandle, ArchivePwd);

      List<string> lstFiles = new List<string>();
      while (iStatus == 0)
      {
        iStatus = RARReadHeaderEx(lHandle, ref uHeader);
        lstFiles.Add(uHeader.FileName);
        Console.WriteLine(uHeader.FileName);
        iStatus2 = RARProcessFile(lHandle, RarOperations.RAR_OP_TEST, sDestPath, null);
      }
      iStatus = RARCloseArchive(lHandle);
      uRAR.OpenMode = RarOpenMode.RAR_OM_EXTRACT;
      lHandle = RAROpenArchiveEx(ref uRAR);
      RarCallbackProcDelegate delOfProc = new RarCallbackProcDelegate(RarCallbackProc);
      RARSetCallback(lHandle, delOfProc, lHandle);
      // open for extract
      while (iStatus == 0)
      {
        iStatus = RARReadHeaderEx(lHandle, ref uHeader);
        iStatus2 = RARProcessFile(lHandle, RarOperations.RAR_OP_EXTRACT, sDestPath, null); 
        ProcessError(iStatus2);
      }
      ProcessError(iStatus);
      Console.WriteLine(uHeader.FileName);
      iStatus = RARCloseArchive(lHandle);
      Console.WriteLine("Status: {0}", iStatus);
    }

    // This procedure is called during extracting of a rar archive

    static string Erro(string Msg)
    {
      Console.WriteLine(Msg);
      return Msg;
    }

static int RarCallbackProc(RarCallbackMessages msg,IntPtr UserData, IntPtr P1, int P2)
{
  int Result = 0;
  switch(msg)
  {
    case RarCallbackMessages.UCM_CHANGEVOLUME:
      if (P2 == (int)RarVol.RAR_VOL_ASK) 
      {
        //CString Info; Info.Format("A volume %s is required, terminate now", ApiGetFileName((char*)P1));
      }
      if (P2 == (int)RarVol.RAR_VOL_NOTIFY)
      {
        // 			CString Path=(char *)P1;
        // pThis->Update_Gui_Info(_T("-Unpacking ") + ApiGetFileName(Path));
      }
        break;
    case RarCallbackMessages.UCM_PROCESSDATA:
        //lKBytesDone += P2; // bytes written so far
        Result = 1;
        break;
      case RarCallbackMessages.UCM_NEEDPASSWORD:
        string ww="sex";
        IntPtr lHandle = UserData;
        RARSetPassword(lHandle, ww);
        break;
      default:
        Result = 1;
      break;
  }
  return Result;
  }

    public static string ProcessError(int ErroNum)
    {
      switch (ErroNum)
      {
        case ERAR_UNKNOWN_FORMAT:
          return Erro("Unknown archive format");
          break;
        case ERAR_BAD_ARCHIVE:
          return Erro("Bad volume");
          break;
        case ERAR_ECREATE:
          return Erro("File create error");
          break;
        case ERAR_EOPEN:
          return Erro("Volume open error");
          break;
        case ERAR_ECLOSE:
          return Erro("File close error");
          break;
        case ERAR_EREAD:
          return Erro("Read error");
          break;
        case ERAR_EWRITE:
          return Erro("Write error");
          break;
        case ERAR_BAD_DATA:
          return Erro("CRC error");
          break;
      }
      return "";
    }

  } // end class
} // end namespace

